package lt.marsrutai.mobile.android.widget;

import java.util.ArrayList;
import java.util.List;

import lt.marsrutai.mobile.android.R;
import lt.marsrutai.mobile.android.fragment.BookmarksFragment.ActionModeManager;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.AdapterView;
import android.widget.CheckBox;
import android.widget.ListView;

import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.actionbarsherlock.view.ActionMode;
import com.actionbarsherlock.view.Menu;

/**
 * <p>
 * A list view with selectable elements. Responsible for managing the action
 * mode.
 * </p>
 * <p>
 * When at least one item is selected - action mode is started. When no elements
 * are selected, the mode is cancelled.
 * </p>
 * 
 * @author Justas
 */
public class SelectableListView extends ListView {

    private SherlockFragmentActivity activity;
    private ActionModeManager actionModeManager;

    private ActionModeCallback actionModeCallback;

    public SelectableListView(Context context) {
        this(context, null, 0);
    }

    public SelectableListView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SelectableListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
        setItemsCanFocus(false);
        setOnItemLongClickListener(new OnItemLongClickListener() {

            @Override
            public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
                // toggle checked state
                boolean isCheckedNewState = !isItemChecked(position);
                setItemChecked(position, isCheckedNewState);

                CheckBox checkBox = (CheckBox) view.findViewById(R.id.checkbox);
                checkBox.setChecked(isCheckedNewState);
                return true;
            }

        });

        activity = (SherlockFragmentActivity) context;
        
        try {
            actionModeManager = (ActionModeManager) context;
        }
        catch (ClassCastException e) {
            throw new IllegalArgumentException("The parent activity must implement ActionModeManager interface.", e);
        }
    }

    @Override
    public void setItemChecked(int position, boolean value) {
        super.setItemChecked(position, value);

        int checkedCount = getCheckedItemPositionList().size();

        if (checkedCount > 0) {
            startActionMode();
            actionModeManager.getActionMode().setTitle(activity.getString(R.string.bookmarks_selected, checkedCount));
        }
        else if (actionModeManager.getActionMode() != null) {
            actionModeManager.getActionMode().finish();
        }
    }

    @Override
    public boolean performItemClick(View view, int position, long id) {
        /*
         * HACK AHEAD
         * 
         * ListView with CHOICE_MODE_MULTIPLE by default toggles item's checked
         * state when a short click is performed (as if the item was a
         * checkbox). We don't want that, but still need the fragment to be
         * notified of the click event.
         * 
         * To work around this issue we pretend that this ListView has
         * CHOICE_MODE_NONE when the item has been clicked and revert back to
         * CHOICE_MODE_MULTIPLE when handling has been finished
         */
        setChoiceMode(ListView.CHOICE_MODE_NONE);
        boolean result = super.performItemClick(view, position, id);
        setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
        return result;
    }

    /**
     * Convenience method for (the useless) {@link #getCheckedItemPositions()}
     * 
     * @return
     */
    public List<Integer> getCheckedItemPositionList() {
        List<Integer> positions = new ArrayList<Integer>();

        for (int i = 0; i < getCount(); i++) {
            if (getCheckedItemPositions().get(i)) {
                positions.add(i);
            }
        }

        return positions;
    }

    public void clearChecked() {
        for (Integer position : getCheckedItemPositionList()) {
            super.setItemChecked(position, false);
        }
    }

    public void startActionMode() {
        if (actionModeManager.getActionMode() == null) {
            actionModeCallback.setActionModeManager(actionModeManager);
            actionModeCallback.setListView(this);
            actionModeManager.setActionMode(activity.startActionMode(actionModeCallback));
        }

        invalidateActionMode();
    }

    public void invalidateActionMode() {
        if (actionModeManager.getActionMode() != null) {
            actionModeManager.getActionMode().invalidate();
        }
    }

    public void setActionModeCallback(ActionModeCallback actionModeCallback) {
        this.actionModeCallback = actionModeCallback;
    }

    public static abstract class ActionModeCallback implements ActionMode.Callback {

        private ActionModeManager actionModeManager;
        private SelectableListView listView;

        @Override
        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
            return true;
        }

        @Override
        public void onDestroyActionMode(ActionMode mode) {
            actionModeManager.setActionMode(null);
            actionModeManager = null;
            listView.clearChecked();
            listView = null;
        }

        public SelectableListView getListView() {
            return listView;
        }

        public void setListView(SelectableListView listView) {
            this.listView = listView;
        }

        public ActionModeManager getActionModeManager() {
            return actionModeManager;
        }

        public void setActionModeManager(ActionModeManager actionModeManager) {
            this.actionModeManager = actionModeManager;
        }

    }

}